放假結束
這裡的就比較抽象一點
再用POSTMAN測試http://localhost:8080/api/customersadd看看修改後新增
選擇BODY然後是JSON檔
{
"customerid": "C0004",
"companyname": "小滋工程",
"address": "台南市",
"phone": "06-1233236",
"email": "huangTZUTZU@cht.com.tw",
"country": "中華民國"
}
程式碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/jquery-3.6.1.min.js}"></script>
<script th:src="@{/ui/sunny/jquery-ui.min.js}"></script>
<!--css-->
<link th:href="@{/ui/sunny/jquery-ui.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.structure.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.theme.min.css}" rel="stylesheet">
<title>客戶新增作業</title>
<!--後端Java變數URL 嵌入成前端JS String變數定義-->
<script th:inline="javascript">
//定義一個變數 儲存新增客戶資料服務位址
var addService=/*[[${custservice}]]*/ "";
</script>
</head>
<body>
<!--顯示URL-->
<fieldset id="app">
<div>{{addCustomersURL}}</div>
<legend>客戶資料維護</legend>
<div>
<button v-on:click="qryHandler">新增客戶資料...</button>
</div>
<!--進行新增對話盒刻版-->
<fieldset id="addDialog" style="display: none;">
<legend>客戶資料新增</legend>
<table>
<tr>
<td>客戶編號</td>
<td><input type="text" v-model:value="customers.customerid"/></td>
</tr>
<tr>
<td>公司行號</td>
<td><input type="text" v-model:value="customers.companyname"/></td>
</tr>
<tr>
<td>聯絡地址</td>
<td><input type="text" v-model:value="customers.address"/></td>
</tr>
<tr>
<td>聯絡電話</td>
<td><input type="text" v-model:value="customers.phone"/></td>
</tr>
<tr>
<td>EMAIL</td>
<td><input type="text" v-model:value="customers.email"/></td>
</tr>
<tr>
<td>國家別</td>
<td><input type="text" v-model:value="customers.country"/></td>
</tr>
</table>
</fieldset>
</fieldset>
<!--Vue Instance個體物件 與掛載作業-->
<script>
//Vue物件
var app=new Vue(
//建構物件初始化 採用JS物件
{
data:{
customers:{
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
},
addCustomersURL:''
},
//定義Vue物件事件模組或者功能模組
methods:{
qryHandler:function(){
//啟動編輯資料的對話盒
console.log('click...');
$('#addDialog').dialog(
//對話盒細部設計
{
title:'客戶新增作業',
modal:true, //強佔式對話盒
width:350,
height:400,
//客製化按鈕
buttons:[
{
text:'關閉',
click:function(){
$('#addDialog').dialog('close');
},
class:''
},
{
text:'新增',
click:function(){
//TODO進行非同步處理
},
class:''
}
]
}
);
}
},
//掛載完成引發事件Life Hook
mounted:function(){
this.addCustomersURL=addService;
}
}
);
//掛載
app.$mount('#app');
</script>
</body>
</html>
再修改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/jquery-3.6.1.min.js}"></script>
<script th:src="@{/ui/sunny/jquery-ui.min.js}"></script>
<!--css-->
<link th:href="@{/ui/sunny/jquery-ui.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.structure.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.theme.min.css}" rel="stylesheet">
<title>客戶新增作業</title>
<!--後端Java變數URL 嵌入成前端JS String變數定義-->
<script th:inline="javascript">
//定義一個變數 儲存新增客戶資料服務位址
var addService=/*[[${custservice}]]*/ "";
</script>
</head>
<body>
<!--顯示URL-->
<fieldset id="app">
<div>{{addCustomersURL}}</div>
<legend>客戶資料維護</legend>
<div>
<button v-on:click="qryHandler">新增客戶資料...</button>
</div>
<!--進行新增對話盒刻版-->
<fieldset id="addDialog" style="display: none;">
<legend>客戶資料新增</legend>
<table>
<tr>
<td>客戶編號</td>
<td><input type="text" v-model:value="customers.customerid"/></td>
</tr>
<tr>
<td>公司行號</td>
<td><input type="text" v-model:value="customers.companyname"/></td>
</tr>
<tr>
<td>聯絡地址</td>
<td><input type="text" v-model:value="customers.address"/></td>
</tr>
<tr>
<td>聯絡電話</td>
<td><input type="text" v-model:value="customers.phone"/></td>
</tr>
<tr>
<td>EMAIL</td>
<td><input type="text" v-model:value="customers.email"/></td>
</tr>
<tr>
<td>國家別</td>
<td><input type="text" v-model:value="customers.country"/></td>
</tr>
</table>
</fieldset>
</fieldset>
<!--Vue Instance個體物件 與掛載作業-->
<script>
//Vue物件
var app=new Vue(
//建構物件初始化 採用JS物件
{
data:{
customers:{
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
},
addCustomersURL:''
},
//定義Vue物件事件模組或者功能模組
methods:{
qryHandler:function(){
//啟動編輯資料的對話盒
console.log('click...');
$('#addDialog').dialog(
//對話盒細部設計
{
title:'客戶新增作業',
modal:true, //強佔式對話盒
width:350,
height:400,
//客製化按鈕
buttons:[
{
text:'關閉',
click:function(){
$('#addDialog').dialog('close');
},
class:''
},
{
text:'新增',
click:function(){
//TODO進行非同步處理
$.ajax(
{
url:app.addCustomersURL,
type:'POST',
beforeSend:function(xhr){
xhr.setRequestHeader("Content-Type","application/json");
},
data:JSON.stringify(app.customers),
success:function(result,status,xhr){
console.log(result);
}
}
);
},
class:''
}
]
}
);
}
},
//掛載完成引發事件Life Hook
mounted:function(){
this.addCustomersURL=addService;
}
}
);
//掛載
app.$mount('#app');
</script>
</body>
</html>
查看資料庫確認新增
目前瀏覽器測試http://localhost:8080/customers/add 顯示
再修改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/jquery-3.6.1.min.js}"></script>
<script th:src="@{/ui/sunny/jquery-ui.min.js}"></script>
<!--css-->
<link th:href="@{/ui/sunny/jquery-ui.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.structure.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.theme.min.css}" rel="stylesheet">
<title>客戶新增作業</title>
<!--後端Java變數URL 嵌入成前端JS String變數定義-->
<script th:inline="javascript">
//定義一個變數 儲存新增客戶資料服務位址
var addService=/*[[${custservice}]]*/ "";
</script>
</head>
<body>
<!--顯示URL-->
<fieldset id="app">
<div>{{addCustomersURL}}</div>
<legend>客戶資料維護</legend>
<div>
<button v-on:click="qryHandler">新增客戶資料...</button>
</div>
<!--進行新增對話盒刻版-->
<fieldset id="addDialog" style="display: none;">
<legend>客戶資料新增</legend>
<table>
<tr>
<td>客戶編號</td>
<td><input type="text" v-model:value="customers.customerid"/></td>
</tr>
<tr>
<td>公司行號</td>
<td><input type="text" v-model:value="customers.companyname"/></td>
</tr>
<tr>
<td>聯絡地址</td>
<td><input type="text" v-model:value="customers.address"/></td>
</tr>
<tr>
<td>聯絡電話</td>
<td><input type="text" v-model:value="customers.phone"/></td>
</tr>
<tr>
<td>EMAIL</td>
<td><input type="text" v-model:value="customers.email"/></td>
</tr>
<tr>
<td>國家別</td>
<td><input type="text" v-model:value="customers.country"/></td>
</tr>
</table>
</fieldset>
</fieldset>
<!--Vue Instance個體物件 與掛載作業-->
<script>
//Vue物件
var app=new Vue(
//建構物件初始化 採用JS物件
{
data:{
customers:{
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
},
addCustomersURL:'',
message:''
},
//定義Vue物件事件模組或者功能模組
methods:{
qryHandler:function(){
//啟動編輯資料的對話盒
console.log('click...');
$('#addDialog').dialog(
//對話盒細部設計
{
title:'客戶新增作業',
modal:true, //強佔式對話盒
width:350,
height:400,
//客製化按鈕
buttons:[
{
text:'關閉',
click:function(){
$('#addDialog').dialog('close');
},
class:''
},
{
text:'新增',
click:function(){
//TODO進行非同步處理
$.ajax(
{
url:app.addCustomersURL,
type:'POST',
beforeSend:function(xhr){
xhr.setRequestHeader("Content-Type","application/json");
},
data:JSON.stringify(app.customers),
success:function(result,status,xhr){
app.message=result.msg;
console.log(result.msg);
},
error:function(xhr,status,error){
app.message=xhr.responseJSON.msg;
console.log(app.message);
}
}
);
},
class:''
}
]
}
);
}
},
//掛載完成引發事件Life Hook
mounted:function(){
this.addCustomersURL=addService;
}
}
);
//掛載
app.$mount('#app');
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/jquery-3.6.1.min.js}"></script>
<script th:src="@{/ui/sunny/jquery-ui.min.js}"></script>
<!--css-->
<link th:href="@{/ui/sunny/jquery-ui.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.structure.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.theme.min.css}" rel="stylesheet">
<title>客戶新增作業</title>
<!--後端Java變數URL 嵌入成前端JS String變數定義-->
<script th:inline="javascript">
//定義一個變數 儲存新增客戶資料服務位址
var addService=/*[[${custservice}]]*/ "";
</script>
</head>
<body>
<!--顯示URL-->
<fieldset id="app">
<div>{{addCustomersURL}}</div>
<legend>客戶資料維護</legend>
<div>
<button v-on:click="qryHandler">新增客戶資料...</button>
</div>
<!--進行新增對話盒刻版-->
<fieldset id="addDialog" style="display: none;">
<legend>客戶資料新增</legend>
<table>
<tr>
<td>客戶編號</td>
<td><input type="text" v-model:value="customers.customerid"/></td>
</tr>
<tr>
<td>公司行號</td>
<td><input type="text" v-model:value="customers.companyname"/></td>
</tr>
<tr>
<td>聯絡地址</td>
<td><input type="text" v-model:value="customers.address"/></td>
</tr>
<tr>
<td>聯絡電話</td>
<td><input type="text" v-model:value="customers.phone"/></td>
</tr>
<tr>
<td>EMAIL</td>
<td><input type="text" v-model:value="customers.email"/></td>
</tr>
<tr>
<td>國家別</td>
<td><input type="text" v-model:value="customers.country"/></td>
</tr>
<div>{{message}}</div>
</table>
</fieldset>
</fieldset>
<!--Vue Instance個體物件 與掛載作業-->
<script>
//Vue物件
var app=new Vue(
//建構物件初始化 採用JS物件
{
data:{
customers:{
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
},
addCustomersURL:'',
message:''
},
//定義Vue物件事件模組或者功能模組
methods:{
qryHandler:function(){
this.message='';
//啟動編輯資料的對話盒
console.log('click...');
$('#addDialog').dialog(
//對話盒細部設計
{
title:'客戶新增作業',
modal:true, //強佔式對話盒
width:350,
height:400,
//客製化按鈕
buttons:[
{
text:'關閉',
click:function(){
$('#addDialog').dialog('close');
},
class:''
},
{
text:'新增',
click:function(){
//TODO進行非同步處理
$.ajax(
{
url:app.addCustomersURL,
type:'POST',
beforeSend:function(xhr){
xhr.setRequestHeader("Content-Type","application/json");
},
data:JSON.stringify(app.customers),
success:function(result,status,xhr){
app.message=result.msg;
console.log(result.msg);
},
error:function(xhr,status,error){
app.message=xhr.responseJSON.msg;
console.log(app.message);
}
}
);
},
class:''
}
]
}
);
}
},
//掛載完成引發事件Life Hook
mounted:function(){
this.addCustomersURL=addService;
}
}
);
//掛載
app.$mount('#app');
</script>
</body>
</html>
修改前端程式碼:後端Java變數URL 嵌入成前端JS String變數定義,掛載完成引發事件Life Hook
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/jquery-3.6.1.min.js}"></script>
<script th:src="@{/ui/sunny/jquery-ui.min.js}"></script>
<!--css-->
<link th:href="@{/ui/sunny/jquery-ui.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.structure.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.theme.min.css}" rel="stylesheet">
<title>客戶新增作業</title>
<!--後端Java變數URL 嵌入成前端JS String變數定義-->
<script th:inline="javascript">
//定義一個變數 儲存新增客戶資料服務位址
var addService=/*[[${custservice}]]*/ "";
</script>
</head>
<body>
<!--顯示URL-->
<fieldset id="app">
<div>{{addCustomersURL}}</div>
<legend>客戶資料維護</legend>
<div>
<button v-on:click="qryHandler">新增客戶資料...</button>
</div>
<!--進行新增對話盒刻版-->
<fieldset id="addDialog" style="display: none;">
<legend>客戶資料新增</legend>
<table>
<tr>
<td>客戶編號</td>
<td><input type="text" v-model:value="customers.customerid"/></td>
</tr>
<tr>
<td>公司行號</td>
<td><input type="text" v-model:value="customers.companyname"/></td>
</tr>
<tr>
<td>聯絡地址</td>
<td><input type="text" v-model:value="customers.address"/></td>
</tr>
<tr>
<td>聯絡電話</td>
<td><input type="text" v-model:value="customers.phone"/></td>
</tr>
<tr>
<td>EMAIL</td>
<td><input type="text" v-model:value="customers.email"/></td>
</tr>
<tr>
<td>國家別</td>
<td><input type="text" v-model:value="customers.country"/></td>
</tr>
</table>
<div>{{message}}</div>
</fieldset>
<!--資料清單-->
<fieldset v-show="isShow" >
<legend>客戶清單</legend>
<table class="table table-dark table-hover">
<thead>
<tr>
<td>客戶編號</td>
<td>公司行號</td>
<td>聯絡地址</td>
<td>連絡電話</td>
<td>EMAIL</td>
<td>國家別</td>
</tr>
</thead>
<tbody>
<tr v-for="item in customersData">
<td>{{item.customerid}}</td>
<td>{{item.companyname}}</td>
<td>{{item.address}}</td>
<td>{{item.phone}}</td>
<td>{{item.email}}</td>
<td>{{item.country}}</td>
</tr>
</tbody>
</table>
</fieldset>
</fieldset>
<!--Vue Instance個體物件 與掛載作業-->
<script>
//Vue物件
var app=new Vue(
//建構物件初始化 採用JS物件
{
data:{
customers:{
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
},
addCustomersURL:'',
message:'',
customersData:[], //空陣列
isShow:false
},
//定義Vue物件事件模組或者功能模組
methods:{
qryHandler:function(){
//reset
this.message='';
this.customers={
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
};//新增的重新設定
//啟動編輯資料的對話盒
console.log('click...');
$('#addDialog').dialog(
//對話盒細部設計
{
title:'客戶新增作業',
modal:true, //強佔式對話盒
width:350,
height:420,
//客製化按鈕
buttons:[
{
text:'關閉',
click:function(){
$('#addDialog').dialog('close');
},
class:''
},
{
text:'新增',
click:function(){
//TODO進行非同步處理 採用jquery ajax
let jsonString=JSON.stringify(app.customers);
console.log(jsonString);
$.ajax(
//採用JS物件設定相關屬性設定
{
url:app.addCustomersURL,
//傳送方式POST
type:'POST',
//Request Header Content-Type:application/json
beforeSend:function(xhr){
xhr.setRequestHeader("Content-Type","application/json");
//...
},
//post上去的Json字串資料 使用內建JSON class方法進明物件序列化
data:jsonString,
//success callback event http status code:2xx
success:function(result,status,xhr){
app.message=result.msg;
//讓Vue資料模組 陣列進行參考這一個相對的物件
//拷貝物件
let newCustomers=Object.assign({},app.customers);
app.customersData.push(newCustomers);
app.isShow=true;
console.log(app.customersData);
},
//http status code:4xx or 5xx
error:function(xhr,status,error){
app.message=xhr.responseJSON.msg;
console.log(app.message);
}
}
);
},
class:''
}
]
}
);
}
},
//掛載完成引發事件Life Hook
mounted:function(){
this.addCustomersURL=addService;
}
}
);
//掛載
app.$mount('#app');
</script>
</body>
</html>
這是一個包含Vue.js的HTML文件,用於客戶資料維護應用程式的前端部分。以下是該HTML檔案的主要特點和功能:
引入必要的JavaScript和CSS庫:
vue.min.js
)、jQuery (jquery-3.6.1.min.js
)、jQuery UI (jquery-ui.min.js
)、Bootstrap (bootstrap.min.js
) 等 JavaScript 庫。使用 th:src
和 th:href
屬性,這些屬性通常是 Thymeleaf 模板引擎使用的,它們可以在後端動態生成URL。在這個HTML中,它們用於動態生成JavaScript和CSS的URL。
在 <script>
區塊中,使用Vue.js建立了一個Vue實例(var app=new Vue({...})
),該實例包含以下功能:
data
物件包含了客戶資料,當前操作的URL、訊息、客戶資料列表和一個控制顯示客戶資料列表的變數。methods
物件包含了 qryHandler
方法,它處理按鈕點擊事件,並彈出一個對話盒,允許用戶輸入客戶資料,然後將資料發送到後端服務。mounted
鉤子(hook)用於在Vue實例成功掛載到HTML之後執行某些代碼,它在這裡用於初始化 addCustomersURL
,這是一個後端服務的URL。HTML 頁面的內容包括:
qryHandler
方法,該按鈕使用 v-on:click
指令綁定事件。#addDialog
),當用戶點擊新增按鈕時,將彈出這個對話盒。這個HTML文件的主要功能是允許用戶新增客戶資料,通過按鈕觸發對話盒,輸入資料,然後將資料以非同步方式發送到後端服務進行處理。成功後,將資料添加到客戶資料列表中,同時顯示相關的訊息。
測試OK
顯示
回到資料庫查看
畫面顯示OK
修改CustomerService後端程式碼,沒修改重複新增會蓋過去
package com.tzu.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.tzu.domain.Customers;
import com.tzu.domain.CustomersRepo;
import com.tzu.domain.CustomersRepository;
import com.tzu.domain.Message;
import com.tzu.domain.StatusMessage;
@RestController
public class CustomerService {
//Data Field注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//注入自訂Repository
@Autowired
private CustomersRepo customersRepo;
//注入JpaRepository 實現DI(Dependency Injection)
@Autowired
private CustomersRepository customersReposit;
//傳遞一份Json進來 進行相對客戶更新作業
//方法參數 採用參數注入Parameter Injection
@PutMapping(path="/api/customers/update/rawdata",
consumes="application/json",produces="application/json")
public Message customersUpdate(@RequestBody Customers customers) {
Message message=new Message();
//更新客戶資料
String sql="update customers set companyname=?,address=?,phone=?,email=?,country=? where customerid=?";
try {
int affect=jdbcTemplate.update(sql,
//Lambda PreparedStatementSetter interface
(st)->{
//注入PreparedStatement物件,設定參數內容
st.setString(1, customers.getCompanyname());
st.setString(2, customers.getAddress());
st.setString(3, customers.getPhone());
st.setString(4, customers.getEmail());
st.setString(5, customers.getCountry());
st.setString(6, customers.getCustomerid());
}
);
if(affect>0) {
message.setCode(200);
message.setMsg("客戶資料更新成功");
}else {
message.setCode(200);
message.setMsg("查無該客戶資料更新");
}
}catch(DataAccessException ex) {
message.setCode(400);
message.setMsg("客戶資料更新失敗");
}
return message;
}
//刪除相對客戶資料
//使用傳遞客戶編號資訊架構 採用QueryString http://xxx.xxx,xxx/xxx/xxx?cid=value&...
@DeleteMapping(path="/api/customers/delete/byid",produces="application/json")
public ResponseEntity<Object> customersDelete(@RequestParam(name="cid") String customerid) {
System.out.println(customersRepo.getTemplate());
var result=customersRepo.delete(customerid);
ResponseEntity<Object> responseEntity=null;
//判斷
if (result>0) {
//刪除成功
Message msg=new Message();
msg.setCode(200);
msg.setMsg("客戶資料刪除成功");
responseEntity=new ResponseEntity<>(msg,HttpStatus.OK);
}else {
//刪除不到資料 回應Http status code-400
StatusMessage msg=new StatusMessage();
msg.setCode(400);
msg.setMsg("沒有這一個客戶");
msg.setErrorCode("notfound");
responseEntity=new ResponseEntity<>(msg,HttpStatus.BAD_REQUEST);
}
return responseEntity;
}
@GetMapping(path="/api/customers/all",produces="application/json")
public List<Customers> jpaCustomersQuery() {
//呼叫方法 找出所有客戶資料(物件)
List<Customers> result=this.customersReposit.findAll();
return result;
}
//傳遞客戶編號 進行相對客戶查詢
@GetMapping(path="/api/customers/{cid}/rawdata",produces="application/json")
public Customers jpaCustomersQryById(@PathVariable("cid")String customerid) {
//借助進來的Jpa 透過自訂的方法進行單筆資料查詢
return this.customersReposit.findByCustomerid(customerid);
}
//傳遞客國家別 進行相對客戶資料查詢
@GetMapping(path="/api/customers/country/{country}/rawdata",produces="application/json")
public List<Customers> jpaCustomersQryByCountry(@PathVariable("country")String country) {
//借助進來的Jpa 透過自訂的方法進行單筆資料查詢
return this.customersReposit.findByCountry(country);
}
//採用參數注入JavaBean
//新增客戶資料
@PostMapping(path="/api/customersadd",produces="application/json",consumes="application/json")
public ResponseEntity<Message> customersInsert(@RequestBody Customers customer) {
//判斷是否有存在這一筆客戶資料???
Message msg=new Message();
ResponseEntity<Message> response=null;
var result=this.customersReposit.findByCustomerid(customer.getCustomerid());
if(result==null) {
//新增作業 採用JPA
Customers oldCustomer=this.customersReposit.save(customer);
msg.setCode(200);
msg.setMsg("客戶新增成功");
response=new ResponseEntity<>(msg,HttpStatus.OK);
}else {
msg.setCode(400);
msg.setMsg("該客戶編號已經存在");
response=new ResponseEntity<>(msg,HttpStatus.BAD_REQUEST);
}
return response;
}
}
這個代碼片段是一個Spring Boot應用程序的RESTful API服務,用於處理客戶資料的CRUD(創建、讀取、更新、刪除)操作。以下是其中一些主要的功能:
使用 @RestController
注解來聲明這是一個RESTful API控制器,它將處理客戶資料的相關操作。
透過 @Autowired
注解注入了 JdbcTemplate
,這是 Spring Framework 提供的用於執行 SQL 查詢的工具。這是對資料庫的低階訪問方式,用於執行 SQL 查詢。
注入了 CustomersRepo
和 CustomersRepository
,這是自定義的資料存取接口,用於更方便地執行 CRUD 操作。
使用不同的 HTTP 方法(@GetMapping
、@PutMapping
、@DeleteMapping
、@PostMapping
)來處理不同的操作:
@PutMapping
: 用於更新客戶資料,接受客戶資料的 JSON,然後根據客戶編號進行更新。@DeleteMapping
: 用於刪除客戶資料,根據客戶編號進行刪除操作,並返回相應的狀態碼。@GetMapping
: 用於查詢客戶資料,可以根據客戶編號或國家進行查詢。@PostMapping
: 用於新增客戶資料,接受客戶資料的 JSON,然後根據客戶編號進行新增。這些方法返回的是 ResponseEntity
,它可以包含 HTTP 狀態碼、訊息和數據,用於向客戶端返回結果。
在一些方法中,使用 JdbcTemplate
執行 SQL 查詢以更新或查詢資料。如果操作成功,返回相應的成功消息,否則返回錯誤消息。
在 @GetMapping
方法中,使用 Spring Data JPA 的方式進行查詢。Spring Data JPA 提供了更高層次的抽象,更容易使用,並支援自定義查詢方法。
總之,這個代碼片段是一個用於處理客戶資料的 RESTful API 服務,它提供了 CRUD 功能,並使用 Spring Framework 和 Spring Data JPA 來簡化操作。
用POSTMAN測試http://localhost:8080/api/customersadd 顯示已經存在
新增後面同步更新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/jquery-3.6.1.min.js}"></script>
<script th:src="@{/ui/sunny/jquery-ui.min.js}"></script>
<!--css-->
<link th:href="@{/ui/sunny/jquery-ui.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.structure.min.css}" rel="stylesheet">
<link th:href="@{/ui/sunny/jquery-ui.theme.min.css}" rel="stylesheet">
<title>客戶新增作業</title>
<!--後端Java變數URL 嵌入成前端JS String變數定義-->
<script th:inline="javascript">
//定義一個變數 儲存新增客戶資料服務位址
var addService=/*[[${custservice}]]*/ "";
</script>
</head>
<body>
<!--顯示URL-->
<fieldset id="app">
<div>{{addCustomersURL}}</div>
<legend>客戶資料維護</legend>
<div>
<button v-on:click="qryHandler">新增客戶資料...</button>
</div>
<!--進行新增對話盒刻版-->
<fieldset id="addDialog" style="display: none;">
<legend>客戶資料新增</legend>
<table>
<tr>
<td>客戶編號</td>
<td><input type="text" v-model:value="customers.customerid"/></td>
</tr>
<tr>
<td>公司行號</td>
<td><input type="text" v-model:value="customers.companyname"/></td>
</tr>
<tr>
<td>聯絡地址</td>
<td><input type="text" v-model:value="customers.address"/></td>
</tr>
<tr>
<td>聯絡電話</td>
<td><input type="text" v-model:value="customers.phone"/></td>
</tr>
<tr>
<td>EMAIL</td>
<td><input type="text" v-model:value="customers.email"/></td>
</tr>
<tr>
<td>國家別</td>
<td><input type="text" v-model:value="customers.country"/></td>
</tr>
</table>
<div>{{message}}</div>
</fieldset>
<!--資料清單-->
<fieldset v-show="isShow" >
<legend>客戶清單</legend>
<table class="table table-dark table-hover">
<thead>
<tr>
<td>客戶編號</td>
<td>公司行號</td>
<td>聯絡地址</td>
<td>連絡電話</td>
<td>EMAIL</td>
<td>國家別</td>
</tr>
</thead>
<tbody>
<tr v-for="item in customersData">
<td>{{item.customerid}}</td>
<td>{{item.companyname}}</td>
<td>{{item.address}}</td>
<td>{{item.phone}}</td>
<td>{{item.email}}</td>
<td>{{item.country}}</td>
</tr>
</tbody>
</table>
</fieldset>
</fieldset>
<!--Vue Instance個體物件 與掛載作業-->
<script>
//Vue物件
var app=new Vue(
//建構物件初始化 採用JS物件
{
data:{
customers:{
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
},
addCustomersURL:'',
message:'',
customersData:[], //空陣列
isShow:false
},
//定義Vue物件事件模組或者功能模組
methods:{
qryHandler:function(){
//reset
this.message='';
this.customers={
customerid:'',
companyname:'',
address:'',
phone:'',
country:'',
email:''
};//新增的重新設定
//啟動編輯資料的對話盒
console.log('click...');
$('#addDialog').dialog(
//對話盒細部設計
{
title:'客戶新增作業',
modal:true, //強佔式對話盒
width:350,
height:420,
//客製化按鈕
buttons:[
{
text:'關閉',
click:function(){
$('#addDialog').dialog('close');
},
class:''
},
{
text:'新增',
click:function(){
//TODO進行非同步處理 採用jquery ajax
let jsonString=JSON.stringify(app.customers);
console.log(jsonString);
$.ajax(
//採用JS物件設定相關屬性設定
{
url:app.addCustomersURL,
//傳送方式POST
type:'POST',
//Request Header Content-Type:application/json
beforeSend:function(xhr){
xhr.setRequestHeader("Content-Type","application/json");
//...
},
//post上去的Json字串資料 使用內建JSON class方法進明物件序列化
data:jsonString,
//success callback event http status code:2xx
success:function(result,status,xhr){
app.message=result.msg;
//讓Vue資料模組 陣列進行參考這一個相對的物件
//拷貝物件
let newCustomers=Object.assign({},app.customers);
app.customersData.push(newCustomers);
app.isShow=true;
console.log(app.customersData);
},
//http status code:4xx or 5xx
error:function(xhr,status,error){
app.message=xhr.responseJSON.msg;
console.log(app.message);
}
}
);
},
class:''
}
]
}
);
}
},
//掛載完成引發事件Life Hook
mounted:function(){
this.addCustomersURL=addService;
}
}
);
//掛載
app.$mount('#app');
</script>
</body>
</html>
再測試一次新增
看資料庫
測試從前端UI新增http://localhost:8080/customers/add
每次新增要refresh
新增後顯示:客戶新增成功
沒有refresh直接按新增客戶紐會有兩筆顯示在畫面上
安全性配置RESTful API
java filter api:https://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html
新增一個package新增一個檔案
要按抽象方法才不會反紅
package com.tzu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ApiKeyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
}
}
這是一個簡單的Servlet過濾器(Filter),用於處理HTTP請求。過濾器通常用於在請求進入Web應用程序之前或響應返回給客戶端之前執行某些操作,如驗證、授權、日誌記錄等。
在這個 ApiKeyFilter
中,doFilter
方法是實現過濾邏輯的地方,但它目前是空的,並沒有定義任何過濾操作。你需要在這個方法中實現你希望過濾器執行的邏輯。
例如,你可以在這個過濾器中檢查HTTP請求的標頭或參數,以確保請求具有有效的 API 金鑰。如果 API 金鑰無效,你可以中斷過濾鏈並返回錯誤響應。
以下是一個簡單的示例,展示如何在 ApiKeyFilter
中檢查 api_key
參數:
public class ApiKeyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String apiKey = httpRequest.getParameter("api_key");
if (isValidApiKey(apiKey)) {
// API金鑰有效,繼續處理請求
chain.doFilter(request, response);
} else {
// API金鑰無效,返回錯誤響應
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
private boolean isValidApiKey(String apiKey) {
// 在這裡實現 API 金鑰驗證邏輯
// 如果 API 金鑰有效,返回true,否則返回false
// 你可以根據你的需求來實現這個方法
return apiKey != null && apiKey.equals("your_valid_api_key");
}
}
這只是一個簡單的示例,你可以根據你的需求自定義更複雜的過濾邏輯。過濾器的主要作用是在HTTP請求進入應用程序之前進行處理,並根據需要修改或拒絕請求。
修改裡面的程式碼
package com.tzu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ApiKeyFilter implements Filter {
//聆聽Filter物件之後引發事件 初始化
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//將兩個參數轉型到Http
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)resp;
System.out.println("Filter 動起來...");
}
}
這個 ApiKeyFilter
是一個標準的Java Servlet過濾器(Filter)類,用於處理HTTP請求。在 doFilter
方法中,你可以實現自己的過濾邏輯以檢查、修改或控制HTTP請求和響應。
在這個範例中,doFilter
方法的開始部分執行了一個簡單的任務,即將傳入的ServletRequest
和ServletResponse
轉型為HttpServletRequest
和HttpServletResponse
。這是因為你通常需要使用HTTP相關的方法和屬性,這些方法和屬性只有在HttpServletRequest
和HttpServletResponse
對象中才能使用。
在你的 ApiKeyFilter
中,你可以繼續添加過濾邏輯,例如驗證API金鑰、修改請求或響應的內容,記錄請求信息,或者進行任何其他需要的操作。
注意,這只是 ApiKeyFilter
的開始部分。實際的過濾邏輯應該在這個方法中實現,並且你也需要在 doFilter
方法的最後調用 chain.doFilter(request, response)
以繼續過濾鏈的執行。如果你希望終止過濾鏈,可以在 doFilter
方法中不調用 chain.doFilter
並發送自定義的響應。
這只是一個起點,你可以根據你的項目需求來實現更複雜的過濾邏輯。
按右鍵選Override
顯示
打V第2個
新增往上移
再修改程式碼:
package com.tzu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApiKeyFilter implements Filter {
//Data Field
private Logger logger=LoggerFactory.getLogger(ApiKeyFilter.class);
//聆聽Filter物件之後引發事件 初始化
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
Filter.super.init(filterConfig);
System.out.println("Filter物件活過來了");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//將兩個參數轉型到Http
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)resp;
logger.info("Filter 服務啟動了");
}
}
ApiKeyFilter
現在已經具有初始化過濾器、啟動過濾器、以及一個簡單的 doFilter
方法,它使用了SLF4J和LoggerFactory,這是一種常見的日誌記錄方式,用於記錄過濾器活動。
在這個更新的 doFilter
方法中,你使用了Logger來記錄一個信息,以示示例過濾器已啟動。當你的應用程序運行時,可以在日誌中查看這些信息,以確保過濾器被呼叫並工作正常。
這只是 ApiKeyFilter
開始部分。你現在可以添加更多的過濾邏輯,以檢查或修改HTTP請求和響應。過濾器可以檢查或攔截特定的HTTP請求,執行驗證、日誌記錄、頁面重定向、加載資源等操作,根據你的項目需求。
繼續在 doFilter
方法中添加的過濾邏輯,然後調用 chain.doFilter(request, response)
以繼續過濾鏈的執行。如果你希望終止過濾鏈,可以在 doFilter
方法中不調用 chain.doFilter
並發送自定義的響應。
這個過濾器的主要目的是監視HTTP請求,所以你可以根據需要檢查、記錄或修改這些請求。根據你的應用程序需求,可以擴展這個過濾器以執行更多操作。
加入@Component()
package com.tzu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component()
public class ApiKeyFilter implements Filter {
//Data Field
private Logger logger=LoggerFactory.getLogger(ApiKeyFilter.class);
//聆聽Filter物件之後引發事件 初始化
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
Filter.super.init(filterConfig);
System.out.println("Filter物件活過來了");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//將兩個參數轉型到Http
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)resp;
logger.info("Filter 服務啟動了");
}
}
已經成功將 ApiKeyFilter
標記為 Spring Component,這將使 Spring 自動檢測它,並將其加入到應用程序上下文。這是一個良好的做法,因為可以利用 Spring 的依賴注入功能。
在過濾器中使用 SLF4J 和 Logger 是一個很好的方式來記錄日誌,特別是在 Web 應用中。你已經使用 logger.info("Filter 服務啟動了")
記錄了一個信息,這是一個很好的開始。
現在,可以繼續擴展的 doFilter
方法,以執行你需要的過濾邏輯,包括檢查或修改 HTTP 請求和響應。這取決於你的應用程序需求,你可以根據需要實現更多的邏輯。
當應用程序運行時,Spring 應該能夠自動檢測並應用你的過濾器,這將使你的過濾器能夠處理 HTTP 請求。
繼續在 doFilter
方法中添加你的過濾邏輯,並使用 chain.doFilter(request, response)
來繼續過濾鏈的執行。根據你的需求,可以執行額外的操作,例如修改 HTTP 響應或中斷過濾鏈的執行。
另一個MywebApplication檔案也要加入package
package com.tzu.myweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EnableJpaRepositories(basePackages= {"com.tzu.domain"})
@EntityScan(basePackages= {"com.tzu.domain"})
@ComponentScan(basePackages = {"com.tzu.controllers","com.tzu.config","com.tzu.service","com.tzu.domain","com.tzu.filter"})
public class MywebApplication {
public static void main(String[] args) {
SpringApplication.run(MywebApplication.class, args);
}
}
Spring Boot 應用程式配置看起來很完整。這是一個典型的 Spring Boot 應用程式設定,包括以下要點:
使用 @SpringBootApplication
標註,它將應用程序視為 Spring Boot 應用程序,啟用自動配置,包括 Spring Boot 的自動掃描和屬性設定。
使用 @EnableJpaRepositories
標註設置 JPA 存儲庫的基本包路徑,讓 Spring Boot 知道在哪裡查找 JPA 存儲庫。
使用 @EntityScan
標註設置實體類的基本包路徑,讓 Spring Boot 知道在哪裡查找 JPA 實體類。
使用 @ComponentScan
標註指示 Spring 框架掃描指定的包路徑以查找 Spring 組件,包括控制器、服務、過濾器等。
這些設定應該可以讓你的應用程式成功運行,Spring Boot 將自動配置所需的項目並設定好應用程式的上下文。
可以運行你的應用程式,Spring Boot 將啟動 Web 伺服器,並根據配置的路徑掃描你的 Controller、Service 和 Filter,使它們能夠處理 HTTP 請求。如果一切正確,你的應用程式應該能夠運行並聆聽指定的端口。
RUN起來用http://localhost:8080/測試
後端顯示:首頁入口
再修改 ApiKeyFilter目前程式碼:
package com.tzu.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component()
@WebFilter(filterName="apikey",urlPatterns= {"/api/*"})
public class ApiKeyFilter implements Filter {
//Data Field
private Logger logger=LoggerFactory.getLogger(ApiKeyFilter.class);
//聆聽Filter物件之後引發事件 初始化
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
Filter.super.init(filterConfig);
System.out.println("Filter物件活過來了");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
//將兩個參數轉型到Http
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)resp;
logger.info("Filter 服務啟動了");
}
}
ApiKeyFilter
類已經設置為一個 Web Filter 並採用 @WebFilter
和 `@Com